# 浅拷贝
# 浅拷贝是指重新分配一块内存,创建一个新的对象,里面的元素是原对象中子对象的引用
# 因此,如果原对象中的元素不可变,那倒无所谓
# 但如果元素可变,浅拷贝通常会带来一些副作用,尤其需要注意
import copy


def shallow_copy():
    print('shallow copy demo:')
    # 浅拷贝方式1:使用数据结构本身的构造函数
    l1 = [1, 2, 3]
    l2 = list(l1)
    print(f'l2: {l2}')
    print(f'l1 == l2: {l1 == l2}')
    print(f'l1 is l2: {l1 is l2}')  # 浅拷贝生成的是另一个对象,与之前的对象ID不同
    s1 = {'a', 'b', 'c'}
    s2 = set(s1)
    print(f's2: {s2}')
    print(f's1 == s2: {s1 == s2}')
    print(f's1 is s2: {s1 is s2}')

    # 浅拷贝方式2: 对于可变的序列,可以通过切片操作符:生成浅拷贝
    l3 = l1[:]
    print(f'l3: {l3}')
    print(f'l1 == l3: {l1 == l3}')
    print(f'l1 is l3: {l1 is l3}')

    # 浅拷贝方式3: 通过内置的copy.copy()函数实现
    l4 = copy.copy(l1)
    print(f'l4: {l4}')
    print(f'l1 == l4: {l1 == l4}')
    print(f'l1 is l4: {l1 is l4}')

    # 注意:对于元组tuple的切片,并不会创建一个浅拷贝的新对象,而是会返回一个指向原始tuple的引用
    t1 = (1, 2, 3)
    t2 = t1[:]
    print(f't2: {t2}')
    print(f't1 == t2: {t1 == t2}')  # 元组是immutable的,所以t1 == t2
    print(f't1 is t2: {t1 is t2}')  # t1和t2是同一个对象


# 深拷贝
# 所谓深度拷贝,是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中
# 因此,新对象和原对象之间完全独立,没有任何关联
# 如果被拷贝的对象较大,包含的属性较多,那么深拷贝可能会带来性能问题,需要谨慎处理
# 如果拷贝对象中存在指向自身的引用,那么程序很容易陷入无限循环
# 深度拷贝函数deepcopy中会维护一个字典,记录已经拷贝的对象与其ID
# 拷贝过程中,如果字典里已经存储了将要拷贝的对象,则会从字典直接返回,这样就有效地解决了深拷贝的死循环问题
def deep_copy():
    print('deep copy demo:')
    # 通过内置函数copy.deepcopy()实现深度拷贝
    l1 = [1, 2, 3]
    l2 = copy.deepcopy(l1)
    print(f'l2: {l2}')
    print(f'l1 == l2: {l1 == l2}')
    print(f'l1 is l2: {l1 is l2}')


if __name__ == '__main__':
    shallow_copy()
    # deep_copy()
